


#include <sstream>
#include "person.h"
#include "catpeople.h"
#include "exppeople.h"



using namespace std;



// ExpAllHumans :: 



ExpAllHumans::ExpAllHumans( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpAllHumans::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllHumans( cat, owner );
}



bool ExpAllHumans::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() != PersonType::HUMAN )
            return !straight(owner);
    }
    return straight(owner);
}



void ExpAllHumans::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a human." : " is a human.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are humans." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a human." : " is not a human.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are not humans." << endl;
        }
    }
}



// ExpAllWizards :: 



ExpAllWizards::ExpAllWizards( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpAllWizards::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllWizards(cat, owner);
}



bool ExpAllWizards::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() != PersonType::WIZARD )
            return !straight(owner);
    }
    return straight(owner);
}



void ExpAllWizards::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a wizard." : " is a wizard.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are wizards." << endl;    
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a wizard." : " is not a wizard.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are not wizards." << endl;
        }
    }
}



// ExpAllVampires :: 



ExpAllVampires::ExpAllVampires( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpAllVampires::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllVampires(cat, owner);
}



bool ExpAllVampires::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() != PersonType::VAMPIRE )
            return !straight(owner);
    }
    return straight(owner);
}



void ExpAllVampires::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a vampire." : " is a vampire.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are vampires." << endl;    
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a vampire." : " is not a vampire.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are not vampires." << endl;    
        }
    }
}



// ExpSomeHumans :: 



ExpSomeHumans::ExpSomeHumans( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpSomeHumans::createExpression( Category *cat, Subject *owner )
{
    if( cat->getCount(owner) > 1 )
        return new ExpSomeHumans( cat, owner );
    else
        return NULL;
}



bool ExpSomeHumans::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() == PersonType::HUMAN )
            return straight(owner);
    }
    return !straight(owner);
}



void ExpSomeHumans::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a human." : " is a human.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are humans." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a human." : " is not a human.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are not humans." << endl;
        }
    }
}



// ExpSomeWizards :: 



ExpSomeWizards::ExpSomeWizards( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpSomeWizards::createExpression( Category *cat, Subject *owner )
{
    if( cat->getCount(owner) > 1 )
        return new ExpSomeWizards(cat, owner);
    else
        return NULL;
}



bool ExpSomeWizards::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() == PersonType::WIZARD )
            return straight(owner);
    }
    return !straight(owner);
}



void ExpSomeWizards::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a wizard." : " is a wizard.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are wizards." << endl;    
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a wizard." : " is not a wizard.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are not wizards." << endl;
        }
    }
}



// ExpSomeVampires :: 



ExpSomeVampires::ExpSomeVampires( Category *cat, Subject *owner )
    : ExpressionCategory( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpSomeVampires::createExpression( Category *cat, Subject *owner )
{
    if( cat->getCount(owner) > 1 )
        return new ExpSomeVampires(cat, owner);
    else
        return NULL;
}



bool ExpSomeVampires::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getType() == PersonType::VAMPIRE )
            return straight(owner);
    }
    return !straight(owner);
}



void ExpSomeVampires::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am a vampire." : " is a vampire.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "Some of " << m_pCategory->putText(owner) << " are vampires." << endl;    
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not a vampire." : " is not a vampire.") << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are not vampires." << endl;    
        }
    }
}



// ExpName ::



ExpName::ExpName( Category *cat, Subject *owner, const char *name )
    : ExpressionCategory(cat)
    , m_szName(name)
{
    m_bInverted = !check(owner);
}



Expression *ExpName::createExpression( Category *cat, Subject *owner, const char *name )
{
    if( cat->getCount() > 1 )
        return new ExpName( cat, owner, name );
    else
        return NULL;
}



bool ExpName::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->getName() == m_szName )
            return straight(owner);
    }
    return !straight(owner);
}



void ExpName::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am " : " is ") << m_szName << '.' << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "One of " << m_pCategory->putText(owner) << " is called " << m_szName << '.' << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << (m_pCategory->personal() ? " am not " : " is not ") << m_szName << '.' << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "None of " << m_pCategory->putText(owner) << " is called " << m_szName << '.' << endl;
        }
    }
}



// ExpAllFat ::



ExpAllFat::ExpAllFat( Category *cat, Subject *owner )
    : ExpressionCategory(cat)
{
    m_bInverted = !check(owner);
}



Expression *ExpAllFat::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllFat(cat, owner);
}



bool ExpAllFat::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( !person->isFat() )
            return !straight(owner);
    }
    return straight(owner);    
}



void ExpAllFat::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is fat." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are fat." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is slim." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "At least one of " << m_pCategory->putText(owner) << " is slim." << endl;
        }
    }    
}
    


// ExpAllSlim ::



ExpAllSlim::ExpAllSlim( Category *cat, Subject *owner )
    : ExpressionCategory(cat)
{
    m_bInverted = !check(owner);
}



Expression *ExpAllSlim::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllSlim(cat, owner);
}



bool ExpAllSlim::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( person->isFat() )
            return !straight(owner);
    }
    return straight(owner);    
}



void ExpAllSlim::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is slim." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " are slim." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is fat." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "At least one of " << m_pCategory->putText(owner) << " is fat." << endl;
        }
    }    
}



// ExpAllIncognito ::



ExpAllIncognito::ExpAllIncognito( Category *cat, Subject *owner )
    : ExpressionCategory(cat)
{
    m_bInverted = !check(owner);
}



Expression *ExpAllIncognito::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllIncognito(cat, owner);
}



bool ExpAllIncognito::check( Subject *owner ) const
{
    const CollectionSubjects &subs = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator is = subs.begin(), is_end = subs.end();
    for( ; is != is_end; ++is )
    {
        Person *person = static_cast <Person*> (*is);
        if( !person->isIncognito() )
            return !straight(owner);
    }
    return straight(owner);
}



void ExpAllIncognito::putText( std::ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() == invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " hides his face." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All of " << m_pCategory->putText(owner) << " hide their faces." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " shows his face." << endl; 
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "At least one of " << m_pCategory->putText(owner) << " shows his face." << endl;
        }
    }
}
